﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using CarolLib.Extension;
using DCS.Business.Interface;
using DCS.Business.Manager;
using DCS.Business.Model;
using DCS.DataProvider;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using CarolLib.WinService;

namespace DCS.BusinessObject
{
    public class Parser : IMessageParser
    {
        #region Members

        static log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private static WinServiceSetting Settings = WinServiceConfiguration.GetConfig().Settings;
        static PFSMessageManager PFSmanager;
        static DCSFileManager DCSmanager;

        #endregion

        #region Regex

        static readonly System.IFormatProvider culture = new System.Globalization.CultureInfo("en-US", true);
        static readonly Regex rgPDate = new Regex("[0-9]{2}[A-Z]{3}[0-9]{2}");
        static readonly Regex rgApt = new Regex("[A-Z]{3} [0-9]{1,3}/[0-9]{1,3}");
        static readonly Regex rgPax = new Regex("[0-9]{1,3}/[0-9]{1,3}");
        static readonly Regex rgAptList = new Regex("-[A-Z]{3}");
        static readonly Regex rgINF = new Regex("INF[0-9]{1,3}");
        static readonly Regex rgStatusCode = new Regex("[A-Z]{5} [0-9]{1,3}[A-Z]{1}");
        static readonly char[] dot = { '.' };
        static readonly char[] slash = { '/' };

        #endregion

        #region IMessageParser Members

        public void Init()
        {
            IUnityContainer myContainer = new UnityContainer();
            UnityConfigurationSection section
              = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Containers["Data"].Configure(myContainer);

            IDataProvider dp = myContainer.Resolve<IDataProvider>();

            PFSmanager = new PFSMessageManager(dp);
            DCSmanager = new DCSFileManager(dp);
        }

        public void DetectAndParse(int batchSize, string messageType)
        {
            List<DCSFileGroup> groups =new List<DCSFileGroup>();

            try
            {
                groups = DCSmanager.GetFilesGroupToParse(batchSize, messageType);
            }
            catch (Exception e)
            {
                Logger.Error("Error in DCSmanager.GetFilesGroupToParse", e);
            }

            if (groups.Sum(d => d.Count()) == 0)
            {
                Logger.Debug("There is no new PFS files. ");
                return;
            }

            List<PFSMessage> results = new List<PFSMessage>();

            Logger.DebugFormat("Begain to parse {0} groups, {1} PFS files", groups.Count, groups.Sum(g => g.Count));

            foreach (var group in groups)
            {
                try
                {
                    results.AddRange(Parse(group));
                    group.ForEach(d => d.Status = FileStatus.FinishParse);
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                    group.ForEach(d => d.Status = FileStatus.ParseError);
                }
            }

            try
            {
                PFSmanager.SaveEntities(results);
                Logger.DebugFormat("Parse {0} PFSMessages successful", results.Count);
                groups.ForEach(g => DCSmanager.UpdateDCSFilesStatus(g));
            }
            catch (Exception e)
            {
                Logger.Error(e);
            }
        }
        
        #endregion

        private List<PFSMessage> Parse(DCSFileGroup group)
        {
            List<PFSMessage> list = new List<PFSMessage>();
            
            PFSMessage model = new PFSMessage();
            string text = group.GroupName;
            model.Carrier = text.Substring(0, 2);
            model.FlightNo = text.Substring(2, text.IndexOf('_') - 2);
            model.PDate = DateTime.ParseExact(rgPDate.Match(text).Value, "ddMMMyy", culture);
            model.DeptAirport = text.Substring(text.Length - 7, 3);

            string CurrentArr = string.Empty;
            string StatusCode=string.Empty;
            string Class = string.Empty;
            int PCount = 0;

            foreach (var file in group.Order())
            {
                using (FileStream fs = new FileStream(file.LocalPath + "\\" + file.LocalFileName, FileMode.Open, FileAccess.Read))
                {
                    model.RefFileId = file.FileId;

                    using (StreamReader reader = new StreamReader(fs, Encoding.UTF8))
                    {
                        text = string.Empty;
                        bool needRead = true;

                        while (!reader.EndOfStream)
                        {
                            try
                            {

                                #region Conditional ReadLine.

                                if (needRead)
                                {
                                    text = reader.ReadLine().Trim();
                                }
                                else
                                {
                                    needRead = true;
                                }

                                #endregion

                                #region 1GUOJING .L/NGMYC4 .F/MU 786231144/C

                                if (text.StartsWith("1"))
                                {
                                    PFSPassenger p = new PFSPassenger();
                                    p.Class = Class;
                                    p.ClassNum = PCount;
                                    p.StatusCode = StatusCode;
                                    //p.MessageId = 

                                    if (text.IndexOf(" ") > 0)
                                    {
                                        p.PName = text.Substring(1, text.IndexOf(" ") - 1).Replace("1", string.Empty);
                                    }
                                    else
                                    {
                                        p.PName = text;
                                    }

                                    if (text.IndexOf(".L/") > 0)
                                    {
                                        if (text.IndexOf(".L/") + 9 > text.Length)
                                        {
                                            p.PNR = text.Substring(text.IndexOf(".L/") + 3).Trim();
                                        }
                                        else
                                        {
                                            p.PNR = text.Substring(text.IndexOf(".L/") + 3, 6).Trim();
                                        }
                                    }
                                    if (text.IndexOf(".F/") > 0)
                                    {
                                        p.FFCard = text.Substring(text.IndexOf(".F/") + 3).Trim();
                                        if (p.FFCard.Length > 17)
                                        {
                                            p.FFCard = p.FFCard.Substring(0, 17).Trim();
                                        }
                                    }

                                    var temp = list.Find(pfs => pfs.ArrAirport == CurrentArr);
                                    temp.PFSPassengers.Add(p);
                                }

                                #endregion

                                #region CFMWL，CHGCL，CHGFL，CHGSG，GOSHN，GOSHO，FQTVN，IDPAD，INVOL，NOREC，NOSHO，OFFLK，OFFLN

                                if (rgStatusCode.IsMatch(text))
                                {
                                    StatusCode = text.Substring(0, 5);
                                    Class = text.Substring(text.Length - 1);
                                    PCount = Convert.ToInt32(text.Substring(6, text.Length - 7));
                                }

                                #endregion

                                #region Message Header

                                //start with 'XXX nnn/nnn'
                                if (rgApt.IsMatch(text))
                                {
                                    PFSMessage temp = model.Clone() as PFSMessage;
                                    temp.PFSPassengers = new List<PFSPassenger>();

                                    temp.ArrAirport = text.Substring(0, 3);

                                    string header = text;

                                    // 000/000/000....
                                    do
                                    {
                                        text = reader.ReadLine();

                                        if (!rgApt.IsMatch(text))
                                        {
                                            header += text.Trim();
                                        }
                                    }
                                    while ((!rgApt.IsMatch(text)) && rgPax.IsMatch(text));
                                    needRead = false;

                                    header = header.Replace(temp.ArrAirport, string.Empty);
                                    if (header.IndexOf("-") > 0)
                                    {
                                        header = header.Substring(0, header.IndexOf("-"));
                                    }

                                    //INFnnn
                                    var inf = rgINF.Match(text);
                                    if (inf.Success)
                                    {
                                        temp.Baby = Convert.ToInt32(inf.Value.Replace("INF", string.Empty));
                                        header.Replace(inf.Value, string.Empty);
                                    }

                                    //PAD nnn/nnn/nnn....
                                    int padidx = header.IndexOf("PAD");
                                    if (padidx > 0)
                                    {
                                        temp.BoardedPassenger = header.Substring(0, padidx).Trim();
                                        temp.PadPassenger = header.Substring(padidx).Trim().Replace("ENDPFS",string.Empty);
                                    }
                                    else
                                    {
                                        temp.BoardedPassenger = text;
                                    }

                                    list.Add(temp);
                                }

                                #endregion

                                #region -KMG

                                if (rgAptList.IsMatch(text))
                                {
                                    CurrentArr = text.Substring(1).Trim();
                                }

                                #endregion

                                #region CFG/015F095Y

                                if (text.StartsWith("CFG/"))
                                {
                                    model.PaxLayout = text.Substring(4);
                                }

                                #endregion

                                #region DIRECT TRANSIT nnn/nnn/nnn/nnn/nnn INFnnn

                                if (text.StartsWith("DIRECT TRANSIT"))
                                {
                                    text = text.Replace("DIRECT TRANSIT", string.Empty).Trim();
                                    int infidx = text.IndexOf("INF");
                                    if (infidx == -1)
                                    {
                                        model.TransitPassenger = text;
                                    }
                                    else
                                    {
                                        model.TransitPassenger = text.Substring(0, infidx).Trim();
                                        model.TransitBaby = Convert.ToInt32(text.Substring(infidx + 3));
                                    }
                                }

                                #endregion

                                #region ENDPFS

                                if (text.StartsWith("ENDPFS"))
                                {
                                }

                                #endregion

                            }
                            catch (Exception ex)
                            {
                                Logger.Error(ex);
                            }
                        }
                    }
                }
            }

            Logger.DebugFormat("Parse {0} OK.", group.GroupName);

            return list;
        }
    }
}
